﻿
using System;
using System.IO;
using System.Linq;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic.Wizards;
using Habanero.Base;
using Habanero.Base.Exceptions;
using Habanero.BO.Loaders;
using Microsoft.Practices.Unity;

namespace FireStarterModeller.Logic
{

    public class ClassDefToSolutionImportProgressEventArgs : EventArgs
    {
        public ClassDefToSolutionImportProgressEventArgs(int progressPercentage)
        {
            ProgressPercentage = progressPercentage;
        }

        public int ProgressPercentage { get; set; }
    }

    public abstract class ClassDefToSolutionImporter
    {
        private string _filename;
        
        protected IUnityContainer IocContainer;
        protected DMSolution TempSolution;
        public DMSolution Solution { protected set; get; }
        public EventHandler<ClassDefToSolutionImportProgressEventArgs> ImportProgressChanged;

        public ClassDefToSolutionImporter(IUnityContainer iocContainer, string filename)
        {
            IocContainer = iocContainer;
            _filename = filename;
            TempSolution = GetSolutionCreator().CreateSolution();
        }


        public abstract DMSolution Import();

        protected void OnImportProgressChanged(int progressPercentage)
        {
            EventHandler<ClassDefToSolutionImportProgressEventArgs> temp = ImportProgressChanged;
            if (temp != null)
                temp(this, new ClassDefToSolutionImportProgressEventArgs(progressPercentage));

        }

        protected static void MarkAllSolutionAssembliesForDelete(DMSolution dmSolution)
        {
            dmSolution.Assemblies.ForEach(assembly => assembly.MarkForDelete());
        }

        protected static void UpdateSolutionNames(DMSolution dmSolution)
        {
            if(dmSolution.DefaultAssembly == null) throw new HabaneroDeveloperException("At least one assembly was expected.  Please ensure that the assembly attribue is set for each class.");
            dmSolution.DefaultAssembly = dmSolution.Assemblies.FirstOrDefault();
            if (string.IsNullOrEmpty(dmSolution.SolutionName) || dmSolution.SolutionName==DMSolution.DEFAULT_NEW_SOLUTION_NAME)
            {
                dmSolution.SolutionName = ExtractSolutionNameFromAssemblyName(dmSolution.DefaultAssembly.AssemblyName);                   
            }
        }

        protected static void ProcessLoadedSolution(DMSolution solution, IUnityContainer container)
        {
            DMSolutionPostLoadProcessor processor = new DMSolutionPostLoadProcessor(container);
            processor.ProcessSolution(solution);
        }

        protected virtual void LoadClassDefsToSolutionForImport(DMSolution dmSolution)
        {
            XmlClassDefsLoader loader = new XmlClassDefsLoader("", new DtdLoader(),
                                                               new FMDefClassFactory(dmSolution));
            loader.LoadClassDefs(File.ReadAllText(_filename));
        }

        public static string ExtractSolutionNameFromAssemblyName(string assemblyName)
        {
            var length = assemblyName.IndexOf(".");
            return length>0 ? assemblyName.Substring(0, length) : assemblyName;
        }


        private SolutionCreator GetSolutionCreator()
        {
            return new SolutionCreator();
        }
    }

    public class ClassDefToNewSolutionImporter : ClassDefToSolutionImporter
    {
        public ClassDefToNewSolutionImporter(IUnityContainer iocContainer, string filename) : base(iocContainer, filename)
        {
        }

        public override DMSolution Import()
        {
            // Moving SetupNewDataAccessor will create duplication of code as it is a private method in ProgramForm.cs
            // and is used in methods not related to the SolutionClassDefLoader
            //SetupNewDataAccessor();

            try
            {
                OnImportProgressChanged(30);
                MarkAllSolutionAssembliesForDelete(TempSolution);
                OnImportProgressChanged(40);
                LoadClassDefsToSolutionForImport(TempSolution);
                OnImportProgressChanged(60);
                UpdateSolutionNames(TempSolution);
                OnImportProgressChanged(70);
                ProcessLoadedSolution(TempSolution, IocContainer);
                OnImportProgressChanged(90);
            }
            catch (Exception ex)
            {
                GlobalRegistry.UIExceptionNotifier.Notify(ex, "", "Error ");
            }

            TempSolution.Save();
            OnImportProgressChanged(99);

            Solution = TempSolution;
            return Solution;

        }

    }
}
